
package com.hlkj.pay.service.payment.impl;
/*
 * Hlpay-Plus aggregate payment system.
 * Copyright (c) 2024-2025 Hlpay Team Copyright has the right of final interpretation.
 */

import java.util.List;

import org.springframework.stereotype.Service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.hlkj.framework.common.pojo.PageResult;
import com.hlkj.framework.common.util.collection.CollectionUtils;
import com.hlkj.framework.common.util.json.JsonUtils;
import com.hlkj.framework.mybatis.core.query.LambdaQueryWrapperX;
import com.hlkj.framework.mybatis.core.query.QueryWrapperX;
import com.hlkj.framework.mybatis.core.utils.MyBatisUtils;
import com.hlkj.pay.app.order.impl.MerchantPaymentHandler;
import com.hlkj.pay.dto.merchant.MerchantPaymentPageStatisticsDto;
import com.hlkj.pay.dto.payment.*;
import com.hlkj.pay.enums.CommonEnum;
import com.hlkj.pay.enums.MerchantEnum;
import com.hlkj.pay.infrastructure.mapper.payment.MerchantPaymentDetailMapper;
import com.hlkj.pay.infrastructure.mapper.payment.MerchantPaymentMapper;
import com.hlkj.pay.infrastructure.model.payment.MerchantPaymentDO;
import com.hlkj.pay.infrastructure.model.payment.MerchantPaymentDetailDO;
import com.hlkj.pay.service.CommonSnFilterService;
import com.hlkj.pay.service.payment.IMerchantPaymentService;

import cn.hutool.core.bean.BeanUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

/**
 * @author HlpayTeam
 * @date 2024/11/20 13:44
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class MerchantPaymentServiceImpl extends CommonSnFilterService implements IMerchantPaymentService {

    private final MerchantPaymentMapper merchantPaymentMapper;

    private final MerchantPaymentDetailMapper merchantPaymentDetailMapper;

    private final MerchantPaymentHandler paymentHandler;

    @Override
    public PageResult<MerchantPaymentPageDto> queryPage(MerchantPaymentPageQueryDto merchantPaymentPageQueryDto) {
        merchantPaymentPageQueryDto.setSortingFields("a.id");
        IPage<MerchantPaymentPageDto> mpPage = MyBatisUtils.buildPage(merchantPaymentPageQueryDto);
        QueryWrapper<MerchantPaymentPageDto> queryWrapper = buildPageWrapper(merchantPaymentPageQueryDto);
        merchantPaymentDetailMapper.selectFilePage(mpPage, queryWrapper);
        return new PageResult(mpPage.getRecords(), mpPage.getTotal(), mpPage.getCurrent(), mpPage.getSize(), mpPage.getPages());
    }

    @Override
    public PageResult<MerchantPaymentDetailDto> queryDetailPage(MerchantPaymentPageQueryDto merchantPaymentPageQueryDto) {
        merchantPaymentPageQueryDto.setSortingFields("b.id");
        IPage<MerchantPaymentDetailDto> mpPage = MyBatisUtils.buildPage(merchantPaymentPageQueryDto);
        QueryWrapper<MerchantPaymentDetailDto> queryWrapper = buildDetailWrapper(merchantPaymentPageQueryDto);
        merchantPaymentDetailMapper.selectDetailPage(mpPage, queryWrapper);
        return new PageResult(mpPage.getRecords(), mpPage.getTotal(), mpPage.getCurrent(), mpPage.getSize(), mpPage.getPages());
    }

    @Override
    public MerchantPaymentPageStatisticsDto merchantPaymentStatistics(MerchantPaymentPageQueryDto merchantPaymentReq) {
        return merchantPaymentDetailMapper.merchantPaymentStatistics(merchantPaymentReq);
    }

    @Override
    public List<MerchantPaymentDetailDto> queryList(MerchantPaymentPageQueryDto merchantPaymentPageQueryDto) {
        QueryWrapperX<MerchantPaymentDetailDto> queryWrapper = new QueryWrapperX<>();
        queryWrapper.eq("a.delete_flag", CommonEnum.YES_NO_TYPE.NO.getCode());
        queryWrapper.eqIfPresent("a.sn", merchantPaymentPageQueryDto.getSn());
        queryWrapper.inIfPresent("a.sn", merchantPaymentPageQueryDto.getSnList());
        queryWrapper.geIfPresent("a.create_time", merchantPaymentPageQueryDto.getStartQueryTime());
        queryWrapper.leIfPresent("a.create_time", merchantPaymentPageQueryDto.getEndQueryTime());
        return merchantPaymentDetailMapper.selectDetailList(queryWrapper);
    }

    @Override
    public List<MerchantPaymentDetailDO> queryDetailList(String paymentId, Integer status) {
        LambdaQueryWrapperX<MerchantPaymentDetailDO> queryWrapper = new LambdaQueryWrapperX<>();
        queryWrapper.eqIfPresent(MerchantPaymentDetailDO::getPaymentId, paymentId);
        queryWrapper.eqIfPresent(MerchantPaymentDetailDO::getStatus, status);
        return merchantPaymentDetailMapper.selectList(queryWrapper);
    }

    @Override
    public MerchantPaymentDto queryDetailDto(String paymentId) {
        MerchantPaymentDO merchantPaymentDO = merchantPaymentMapper.selectOne(MerchantPaymentDO::getPaymentId, paymentId);
        if (merchantPaymentDO == null) {
            return null;
        }
        MerchantPaymentDto merchantPaymentDto = BeanUtil.copyProperties(merchantPaymentDO, MerchantPaymentDto.class);
        List<MerchantPaymentDetailDO> merchantPaymentDetailList = merchantPaymentDetailMapper.selectList(MerchantPaymentDetailDO::getPaymentId, paymentId);
        if (CollectionUtils.isNotEmpty(merchantPaymentDetailList)) {
            merchantPaymentDto.setMerchantPaymentDetailList(merchantPaymentDetailList);
        }
        return merchantPaymentDto;
    }

    @Override
    public MerchantPaymentDO queryDetail(String paymentId) {
        return merchantPaymentMapper.selectOne(MerchantPaymentDO::getPaymentId, paymentId);
    }

    @Override
    public void updatePayment(MerchantPaymentDto merchantPaymentDto) {
        MerchantPaymentDO merchantPaymentDO = new MerchantPaymentDO();
        merchantPaymentDO.setId(merchantPaymentDto.getId());
        merchantPaymentDO.setStatus(merchantPaymentDto.getStatus());
        merchantPaymentMapper.updateById(merchantPaymentDO);
        merchantPaymentDto.getMerchantPaymentDetailList().forEach(merchantPaymentDetailDO -> {
            MerchantPaymentDetailDO merchantPaymentDetail = new MerchantPaymentDetailDO();
            merchantPaymentDetail.setId(merchantPaymentDetailDO.getId());
            merchantPaymentDetail.setStatus(merchantPaymentDetailDO.getStatus());
            merchantPaymentDetail.setRemark(merchantPaymentDetailDO.getRemark());
            log.info("代付状态更新 detailPaymentId:{},merchantPaymentDetail:{}", merchantPaymentDetailDO.getDetailPaymentId(), JsonUtils.toJsonString(merchantPaymentDetail));
            merchantPaymentDetailMapper.updateById(merchantPaymentDetail);
        });
    }

    @Override
    public void updatePayment(MerchantPaymentDO merchantPaymentDO) {
        merchantPaymentMapper.updateById(merchantPaymentDO);
    }

    @Override
    public void addPayment(MerchantPaymentDto merchantPaymentDto) {
        merchantPaymentMapper.insert(merchantPaymentDto);
        merchantPaymentDetailMapper.insertBatch(merchantPaymentDto.getMerchantPaymentDetailList());
        //代付统计
        paymentHandler.sendStatistics(merchantPaymentDto);
    }

    @Override
    public void addPaymentList(List<MerchantPaymentDto> merchantPaymentDtos) {
        merchantPaymentDtos.stream().forEach(merchantPaymentDto -> {
            addPayment(merchantPaymentDto);
        });
    }

    @Override
    public List<MerchantPaymentStatisticsDto> statistics(MerchantPaymentPageQueryDto merchantPaymentReq, String groupBy) {
        QueryWrapperX<MerchantPaymentPageDto> queryWrapper = new QueryWrapperX<>();
        queryWrapper.eq("p.delete_flag", CommonEnum.YES_NO_TYPE.NO.getCode());
        queryWrapper.eq("d.delete_flag", CommonEnum.YES_NO_TYPE.NO.getCode());
        queryWrapper.eq("d.sn", merchantPaymentReq.getSn());
        queryWrapper.inIfPresent("d.sn", merchantPaymentReq.getSnList());
        queryWrapper.geIfPresent("d.create_time", merchantPaymentReq.getStartQueryTime());
        queryWrapper.leIfPresent("d.create_time", merchantPaymentReq.getEndQueryTime());
        queryWrapper.groupBy(groupBy);
        return merchantPaymentDetailMapper.statisticsByWhere(queryWrapper);
    }

    @Override
    public int updatePaymentDetail(MerchantPaymentDetailDO merchantPaymentDetailDO) {
        LambdaQueryWrapperX<MerchantPaymentDetailDO> queryWrapper = new LambdaQueryWrapperX<>();
        queryWrapper.eq(MerchantPaymentDetailDO::getDetailPaymentId, merchantPaymentDetailDO.getDetailPaymentId());
        queryWrapper.neIfPresent(MerchantPaymentDetailDO::getStatus, merchantPaymentDetailDO.getStatus());
        return merchantPaymentDetailMapper.update(merchantPaymentDetailDO, queryWrapper);
    }

    @Override
    public void addPaymentDetail(MerchantPaymentDetailDO merchantPaymentDetailDO) {
        merchantPaymentDetailMapper.insert(merchantPaymentDetailDO);
    }

    @Override
    public MerchantPaymentDetailDO queryPaymentDetail(String detailPaymentId) {
        return merchantPaymentDetailMapper.selectOne(MerchantPaymentDetailDO::getDetailPaymentId, detailPaymentId);
    }

    @Override
    public void updatePaymentStatus(String paymentId, MerchantEnum.PROCESS_STATUS paymentType) {
        MerchantPaymentDO merchantPaymentDO = new MerchantPaymentDO();
        merchantPaymentDO.setStatus(paymentType.getCode());
        LambdaQueryWrapperX<MerchantPaymentDO> queryWrapper = new LambdaQueryWrapperX<>();
        queryWrapper.eqIfPresent(MerchantPaymentDO::getPaymentId, paymentId);
        merchantPaymentMapper.update(merchantPaymentDO, queryWrapper);
    }

    @Override
    public MerchantPaymentDetailDO queryPaymentDetailByMchOrder(String mchOrderNo) {
        return merchantPaymentDetailMapper.selectOne(MerchantPaymentDetailDO::getMchOrderNo, mchOrderNo);
    }

    /**
     * 查询条件封装
     *
     * @param merchantPaymentPageQueryDto
     * @return
     */
    QueryWrapper<MerchantPaymentPageDto> buildPageWrapper(MerchantPaymentPageQueryDto merchantPaymentPageQueryDto) {
        filterSn(merchantPaymentPageQueryDto);
        QueryWrapperX<MerchantPaymentPageDto> queryWrapper = new QueryWrapperX<>();
        queryWrapper.eq("a.delete_flag", CommonEnum.YES_NO_TYPE.NO.getCode());
        queryWrapper.eqIfPresent("a.sn", merchantPaymentPageQueryDto.getSn());
        queryWrapper.inIfPresent("a.sn", merchantPaymentPageQueryDto.getSnList());
        queryWrapper.eqIfPresent("a.payment_id", merchantPaymentPageQueryDto.getPaymentId());
        queryWrapper.eqIfPresent("a.detail_payment_id", merchantPaymentPageQueryDto.getDetailPaymentId());
        queryWrapper.eqIfPresent("a.provider_code", merchantPaymentPageQueryDto.getProviderCode());
        queryWrapper.eqIfPresent("a.channel_code", merchantPaymentPageQueryDto.getChannelCode());
        queryWrapper.eqIfPresent("a.app_id", merchantPaymentPageQueryDto.getAppId());
        queryWrapper.eqIfPresent("a.mch_channel_code", merchantPaymentPageQueryDto.getMchChannelCode());
        queryWrapper.eqIfPresent("a.status", merchantPaymentPageQueryDto.getStatus());

        queryWrapper.geIfPresent("a.pay_amount", merchantPaymentPageQueryDto.getMinPayAmount());
        queryWrapper.leIfPresent("a.pay_amount", merchantPaymentPageQueryDto.getMaxPayAmount());
        queryWrapper.geIfPresent("a.create_time", merchantPaymentPageQueryDto.getStartQueryTime());
        queryWrapper.leIfPresent("a.create_time", merchantPaymentPageQueryDto.getEndQueryTime());
        queryWrapper.leIfPresent("a.entry_type", merchantPaymentPageQueryDto.getEntryType());
        queryWrapper.leIfPresent("a.payee_type", merchantPaymentPageQueryDto.getPayeeType());
        queryWrapper.leIfPresent("a.payment_type", merchantPaymentPageQueryDto.getPaymentType());
        return queryWrapper;
    }

    /**
     * 查询条件封装
     *
     * @param merchantPaymentPageQueryDto
     * @return
     */
    QueryWrapper<MerchantPaymentDetailDto> buildDetailWrapper(MerchantPaymentPageQueryDto merchantPaymentPageQueryDto) {
        filterSn(merchantPaymentPageQueryDto);
        QueryWrapperX<MerchantPaymentDetailDto> queryWrapper = new QueryWrapperX<>();
        queryWrapper.eq("b.delete_flag", CommonEnum.YES_NO_TYPE.NO.getCode());
        queryWrapper.eq("a.delete_flag", CommonEnum.YES_NO_TYPE.NO.getCode());
        queryWrapper.eqIfPresent("a.sn", merchantPaymentPageQueryDto.getSn());
        queryWrapper.eqIfPresent("a.entry_type", merchantPaymentPageQueryDto.getEntryType());
        queryWrapper.inIfPresent("a.sn", merchantPaymentPageQueryDto.getSnList());
        queryWrapper.eqIfPresent("a.payment_id", merchantPaymentPageQueryDto.getPaymentId());
        queryWrapper.eqIfPresent("a.provider_code", merchantPaymentPageQueryDto.getProviderCode());
        queryWrapper.eqIfPresent("a.channel_code", merchantPaymentPageQueryDto.getChannelCode());
        queryWrapper.eqIfPresent("a.app_id", merchantPaymentPageQueryDto.getAppId());
        queryWrapper.eqIfPresent("a.mch_channel_code", merchantPaymentPageQueryDto.getMchChannelCode());
        queryWrapper.eqIfPresent("b.status", merchantPaymentPageQueryDto.getStatus());
        queryWrapper.geIfPresent("b.pay_amount", merchantPaymentPageQueryDto.getMinPayAmount());
        queryWrapper.leIfPresent("b.pay_amount", merchantPaymentPageQueryDto.getMaxPayAmount());
        queryWrapper.geIfPresent("b.create_time", merchantPaymentPageQueryDto.getStartQueryTime());
        queryWrapper.leIfPresent("b.create_time", merchantPaymentPageQueryDto.getEndQueryTime());
        queryWrapper.eqIfPresent("b.ins_order_no", merchantPaymentPageQueryDto.getInsOrderNo());
        queryWrapper.eqIfPresent("b.third_payment_id", merchantPaymentPageQueryDto.getThirdPaymentId());
        queryWrapper.eqIfPresent("b.detail_payment_id", merchantPaymentPageQueryDto.getDetailPaymentId());
        queryWrapper.eqIfPresent("b.mch_order_no", merchantPaymentPageQueryDto.getMchOrderNo());
        queryWrapper.eqIfPresent("b.channel_order_id", merchantPaymentPageQueryDto.getChannelOrderId());
        queryWrapper.eqIfPresent("a.payment_type", merchantPaymentPageQueryDto.getPaymentType());
        queryWrapper.eqIfPresent("b.name", merchantPaymentPageQueryDto.getName());
        queryWrapper.eqIfPresent("b.card_no", merchantPaymentPageQueryDto.getCardNo());
        return queryWrapper;
    }
}
